/*  tBookShelf: TextPlugin
    (C) 2007  TvN (Volodymyr Tarasenko), e-mail: tvntsr@yahoo.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdio.h>
#include <time.h>
#include <math.h>
#include <stdlib.h>
#include <unistd.h>

#include <iostream>
#include <vector>
#include <memory>

#include <hlapi.h>
#include <assert.h>

#include "TextPluginN.hpp"

/*

*/

using namespace std;

ofstream trace("/mnt/log.txt");

static CallbackFunction * v3_callbacks = 0;
static TextReader*        txt_reader   = 0;
static Page*              curr_page    = 0;

static viewer_menu_item_t custom_menu = { 0, 0, 0 };

int IsStandardStatusBarVisible()
{
    TRACE;
    return 1; // Allow use standard status bar
}

void SetCallbackFunction(struct CallbackFunction *cb)
{
    TRACE;
    v3_callbacks = cb;
}

int  InitDoc(char* fileName)
{
    TRACE_MSG("File:" << fileName);

    assert(fileName);
    try
    {
        char *main_cfg_file = getenv("TextReaderCfg");
        if(!main_cfg_file)
        {
            main_cfg_file = "/etc/textplugin.lua";
        }
        TRACE_MSG("CFG file is:" << main_cfg_file);

        auto_ptr<HyphenationManager> hyph_man(
            new HyphenationManager());

        auto_ptr<ConfigParser> config(
            new ConfigParser(main_cfg_file, 
                             fileName,
                             hyph_man.get()));
        
        initDebug(config.get());
        TRACE_MSG("log file initialed");
        
        auto_ptr<FontManager> font_man(
            new FontManager());

        font_man->setHyphenationManager(hyph_man.get());

        dout << "Create doc: file " << fileName << endl;

        int max_page_cache = config->getPageCacheSize();
        if (max_page_cache == 0)
        {
            max_page_cache = DEFAULT_MAX_PAGE_CACHE;
        }

        txt_reader = new TextReader;
        
        txt_reader->registerConfigManager(config);
        txt_reader->registerFontManager(font_man);
        txt_reader->registerHyphenationManager(hyph_man);

        auto_ptr<PageCacheManager> page_man(
            new PageCacheManager(max_page_cache));

        txt_reader->registerCacheManager(page_man);

        auto_ptr<StreamManager> smanager(
            new StreamManager);
        
        txt_reader->registerStreamManager(smanager);

        dout << "fileName:"
             << fileName
             << endl;

        txt_reader->setPageOrientation(Portrait);

        dout << "Open file" << endl;
        int pageNum = txt_reader->open(fileName);
        dout << "Open successsful" << endl;

    }catch(exception& exc)
    {
        TRACE_MSG(":Error " << exc.what());
        dout << __FUNCTION__ << ":Error " << exc.what()
             << endl;

        return 0;
    }
    catch(...)
    {
        TRACE_MSG("Unknown exception");
        dout << __FUNCTION__ << ": Unknown exception" << endl;
        return 0;
    }

    return 1;
}

void   vEndDoc()
{
    TRACE;

    delete txt_reader;

    txt_reader = 0;
}

#ifdef NANO_X
void vSetDisplayState(Apollo_State *)
{
    TRACE;
}
#endif

// Initiale  Font subsystem
int iInitDocF(char *filename,int pageNo, int flag)
{
    TRACE_MSG("File:"        << filename
              << ", PageNo:" << pageNo
              << ", flag:"   << flag);
    try{
        if ((txt_reader)&&(curr_page))
            txt_reader->cacheManager().releasePage(curr_page);

        curr_page = txt_reader->cacheManager().getPage(pageNo);
    }catch(std::exception& err)
    {
        TRACE_MSG("Error:"<< err.what());
    }

    return 0;
}

int iGetDocPageWidth()
{
    TRACE;
    PageOrientation orient = txt_reader->getPageOrientation();

    return txt_reader->configManager().getPageWidth(orient);
}

int iGetDocPageHeight()
{
    TRACE;
    PageOrientation orient = txt_reader->getPageOrientation();

    return txt_reader->configManager().getPageHeight(orient);
}

void GetPageDimension(int *width, int *height)
{
    TRACE;

    PageOrientation orient = txt_reader->getPageOrientation();

    *height = txt_reader->configManager().getPageHeight(orient);

    *width  = txt_reader->configManager().getPageWidth(orient);
}


int  bGetRotate()
{
    TRACE;

    return 0;
}

void vSetCurPage(int num) 
{
    TRACE_MSG("Page num is " << num);

    try{
        if (txt_reader)
            txt_reader->cacheManager().releasePage(curr_page);
        
        curr_page = (txt_reader->cacheManager().isPageAvailable(num))?
            txt_reader->cacheManager().getPage(num):
            txt_reader->cacheManager().getLastPage();
    }
    catch(std::exception& err)
    {
        TRACE_MSG("Error:" << err.what());
    }
}

int  GetPageNum()
{
    TRACE;

    return txt_reader->getPageCount();
}

void vGetTotalPage(int *a)
{
    TRACE;

    *a = txt_reader->getPageCount();
}

int GotoPage(int index)
{
    TRACE_MSG("Goto page " << index);

    try{
        if ((index < 0) || (index > txt_reader->getPageCount()))
            return 0;

        if (curr_page)
        {
            if (curr_page->num = index)
                return 1;
            
            txt_reader->cacheManager().releasePage(curr_page);
        }
        curr_page = txt_reader->cacheManager().getPage(index);
    }
    catch(std::exception& err)
    {
        TRACE_MSG("Error:" << err.what());
        return 0;
    }

    return 1;
}

int  GetPageIndex()
{
    TRACE;

    return (curr_page)? curr_page->num : 0;
}

int Prev()
{
    TRACE;
    
    int index = curr_page ? curr_page->num : 0;
    --index;
    if (index <= 0)
    {
        TRACE_MSG("First page already shown");
        return 0;
    }
    if (curr_page)
        txt_reader->cacheManager().releasePage(curr_page);

    curr_page = txt_reader->cacheManager().getPage(index);

    return 1;
}

int Next()
{
    TRACE;

    int index = curr_page ? curr_page->num : 0;
    ++index;

    if (index > txt_reader->getPageCount())
    {
        TRACE_MSG("Last page already shown");
        return 0;
    }
    if (curr_page)
        txt_reader->cacheManager().releasePage(curr_page);

    curr_page = txt_reader->cacheManager().getPage(index);

    return 1;
}


void GetPageData(void **data)
{
    TRACE;
    *data = 0;

    if (!curr_page)
    {
        TRACE_MSG("There is no current page");
        return;
    }

    TRACE_MSG("Current page:"<< curr_page->num);
    try{
        txt_reader->renderPage(curr_page);

        //*data = curr_page->area->buffer;
        *data = curr_page->area->buffer;
    }
    catch(std::exception &exc)
    {
        TRACE_MSG("Render error:"
                  << exc.what());
        dout << "Render error:" << exc.what()
             << endl;
    }

    TRACE_MSG("Copied");
}
void SetPageDimension(int width, int height)
{
    TRACE_MSG("Set page width to " << width
              << ", height to " << height);
}

int OnStatusInfoChange( status_info_t * statusInfo, myRECT * rectToUpdate )
{
    TRACE_MSG("bookmarkLabelFlags:" << statusInfo->bookmarkLabelFlags
              << ", musicState:"    << statusInfo->musicState
              << ", batteryState:"  << statusInfo->batteryState
              << ", currentBookmarkFlags:" << statusInfo->currentBookmarkFlags); 

    return 0;
}

int OnKeyPressed(int keyId, int state)
{
    TRACE_MSG("Pressed Key:" << keyId
              << ", state: " << state);
    return 0;
}

const viewer_menu_item_t * GetCustomViewerMenu()
{
    TRACE;

    return &custom_menu;
}

//
// Next should be implemented
//
void vSetRotate(int)
{
    TRACE;
}

int Bigger()
{
    TRACE;
    return 0;
}
int Smaller()
{
    TRACE;
    return 0;
}
int Rotate()
{
    TRACE;
    return 0;
}
int Fit()
{
    TRACE;
    return 0;
}

int Origin()
{
    TRACE;
    return 0;
}
void Release()
{
    TRACE;
}

void SetPageDimension_l(int width, int height)
{
    TRACE;
}
double dGetResizePro()
{
    TRACE;
    return 0.0;
}
void vSetResizePro(double dSetPro)
{
    TRACE;
}
    
void bGetUserData(void **vUserData, int *iUserDataLength)
{
    TRACE;
}

void vSetUserData(void *vUserData, int iUserDataLength)
{
    TRACE;
}

    
unsigned short usGetLeftBarFlag()
{
    TRACE;
    return 0;
}

void   vEndInit(int iEndStyle)
{
    TRACE_MSG("EndStyle is " << iEndStyle);
}

void   vFirstBmp(char *, int)
{
    TRACE;
}

int       iGetCurDirPage(int, int)
{
    TRACE;
    return 0;
}

int       iGetDirNumber()
{
    TRACE;
    return 0;
}

unsigned short* usGetCurDirName(int, int)
{
    TRACE;

    return 0;
}

int       iGetCurDirLen(int, int)
{
    TRACE;

    return 0;
}

void   vClearAllDirList()
{
    TRACE;
}

int   bCurItemIsLeaf(int pos)
{
    TRACE;

    return 0;
}

void   vEnterChildDir(int pos)
{
    TRACE;
}

void   vReturnParentDir()
{
    TRACE;
}

void   vFreeDir()
{
    TRACE;
}

int OnMenuAction( int actionId )
{
    TRACE;

    return 0;
}

const char * GetCurrentPositionBookmark()
{
    TRACE;

    return 0;
}

void GoToBookmark( const char * bookmark )
{
    TRACE;
}

int GetBookmarkPage( const char * bookmark )
{
    TRACE;

    return 0;
}


const char * GetAboutInfoText()
{
    TRACE;

    return 0;
}

unsigned short * szGetVoiceDataBlock( int iPage, 
                                      int * numChars, 
                                      int * encodingType )
{
    TRACE;

    return 0;
}

int getBatteryState()
{
    TRACE;
}

void setStatusMode( int newMode )
{
    TRACE;
}

int EndMenuDialogState( int option )
{
    TRACE;

    return 0;
}
void enableBookmarkIcons( bool enable )
{
    TRACE;
}
void vFontBigger()
{
    TRACE;
}
int	iCreateDirList()
{
    TRACE;
    return 0;
}
unsigned short* usGetCurDirNameAndLen(int pos, int * len)
{
    TRACE;
    return 0;
}
int OpenLeaf( int pos )
{
    TRACE;

    return 0;
}
